package main

import (
	"fmt"
)

// 我们定义了一个新类型 Integer
type Integer int

func (a Integer) Less(b Integer) bool {
	return a < b
}

func (a *Integer) Add(b Integer) {
	*a += b
}

func (a Integer) Add2(b Integer) {
	a += b
}

type Rect struct {
	x, y          float64
	width, height float64
}

// 虚拟构造函数
func NewRect(x, y, width, height float64) *Rect {
	return &Rect{x, y, width, height}
}

// 3.1 类型系统
func main() {
	// 在Go语言中，你可以给任意类型（包括内置类型，但不包括指针类型）添加相应的方法
	//	var a Integer = 1
	//	if a.Less(2) {
	//		fmt.Println(a, "Less 2")
	//	}
	//	var b Integer = 11
	//	a.Add(b)
	//	fmt.Println(a)

	//	// 类型都是基于值传递的,要想修改变量的值，只能传递指针。
	//	a.Add2(b)
	//	fmt.Println(a)

	// Go语言中的大多数类型都基于值语义
	// Go语言中类型的值语义表现得非常彻底。我们之所以这么说，是因为数组
	//	var a = [3]int{1, 2, 3}
	//	var b = a
	//	b[1]++
	//	fmt.Println(a, b) // [1 2 3] [1 3 3]。 b=a 赋值语句是数组内容的完整复制

	//	var b = &a
	//	b[1]++ // 指针指向内容加1
	//	fmt.Println(a, *b)

	// Go语言中有4个类型比较特别，看起来像引用类型
	//   数组切片：指向数组（array）的一个区间。
	//   map：极其常见的数据结构，提供键值查询能力。
	//   channel：执行体（goroutine）间的通信设施。
	//   接口（interface）：对一组满足某个契约的类型的抽象。

	// Go语言的结构体（struct）和其他语言的类（class）有同等的地位，但Go语言放弃了包括继承在内的大量面向对象特性，只保留了组合（composition）这个最基础的特性。
	// 3.2 初始化
	// 未进行显式初始化的变量都会被初始化为该类型的零值，例如 bool 类型的零值为 false ， int 类型的零值为0， string 类型的零值为空字符串。
	// 在Go语言中没有构造函数的概念，对象的创建通常交由一个全局的创建函数来完成，以NewXXX 来命名，表示“构造函数”
	//	rect1 := new(Rect)
	//	rect2 := &Rect{}
	//	rect3 := &Rect{0, 0, 100, 200}
	//	rect4 := &Rect{width: 100, height: 200}

	//	rect4 := NewRect(0, 0, 100, 200)
	//	fmt.Println(rect4.Area())
	rect1 := new(Rect)
	rect1.width = 10
	rect1.height = 20
	fmt.Println(rect1)
	fmt.Println(rect1.Area())

	rect3 := &Rect{0, 0, 100, 200}
	fmt.Println(rect3)
}

func (r *Rect) Area() float64 {
	return r.width * r.height
}
